/*
 * GeoVISTA Center (Penn State, Dept. of Geography)
 * Copyright (c), 2003-2011,  Jin Chen and Alan M. MacEachren, GeoVISTA Center, Penn State University
 * Licensed under Simplified BSD License
 *
 *
 * @author: jin Chen 
 * @date: Jun 6, 2007$
 * @version: 1.0
 */
package edu.psu.geovista.app.hce.dendroview;

import edu.psu.geovista.app.hce.clustering.model.BCluster;
import edu.psu.geovista.app.hce.clustering.model.ClusterModel;
import edu.psu.geovista.app.hce.clustering.model.DfLCluster;
import edu.psu.geovista.app.hce.clustering.model.LCluster;
import edu.psu.geovista.app.hce.dendroview.gui.layout.DendrogramPlotSizes2;
import edu.psu.geovista.app.hce.dendroview.gui.layout.PlotSize;
import edu.psu.geovista.app.hce.dendroview.node.BNode;
import edu.psu.geovista.app.hce.dendroview.node.BNodeFactory;
import edu.psu.geovista.app.hce.dendroview.node.HorizontalBNode;
import edu.psu.geovista.app.hce.dendroview.node.VerticalBNode;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

public class Demdrog3 extends JPanel  {

    public static final String Change_BarSetting="barset";

    private static final boolean DEBUG=false;
    //datamodel
    int orient=3;//5;
    
    int distance;
    List<Point> leafsloc;
    protected PlotSize sizes;
    protected  BNode node=new VerticalBNode();
    BCluster rnode;
    List <DfLCluster> leafs;  // 
    List clusters;   // 
    int nbCluster;// 
    JComponent mainp; //main panel?
    ComponentAdapter compadpt;
    protected BNodeFactory factory;
    PropertyChangeSupport prop;
    int nbLeafCluster;// 
    double maxsim;
    double minsim;


    public Demdrog3(int orient) {

        setOrient(orient);//must
        init();

    }

    protected  void init() {
        //factory=new BNodeFactory();
        DendrogramPlotSizes2 sizes = new DendrogramPlotSizes2() ;//getDefaultPlotsize();

        // sizes.setOffsetsize(new Dimension(0,100));
        this.sizes=sizes;
        this.node.setOrient(this.getOrient() );



        compadpt=new ComponentAdapter() {
            public void componentResized(ComponentEvent e) {
                Component component = e.getComponent();
                final Dimension size = component.getSize();
                SwingUtilities.invokeLater(new Runnable(){

                    public void run() {
                        setsizes(size);
                        revalidate();
                        repaint();
                    }
                });

            }
        };
        this.addComponentListener(compadpt);
        //install bar
        this.setLayout(null);


        prop=new PropertyChangeSupport(this);

    }
    /*******************************************************************************************************
     *                GUI
     *******************************************************************************************************/
    public void setInfo(BCluster rnode, List lfs,List clsts,int nbcls,int nblfcls,double min, double max){
          this.rnode=rnode;
          this.leafs=lfs;
          this.clusters =clsts;
          this.nbCluster=nbcls;
          this.nbLeafCluster=nblfcls;
          this.minsim =min;
          this.maxsim=max;
     }
    protected void computeDistance(){
        int orient = this.getOrient();
        PlotSize sizes = this.getSizes();
        Dimension graphsize = sizes.getGraphsize();


    }

    protected void computeLeafsLocation(){

    }
     public void setClustermodel(ClusterModel clustermodel) {
         
     }
    public void setOrient(int orient) {
        this.orient = orient;

        BNode node = createNode(orient);
        this.setNode(node);

        this.repaint();

    }

    private BNode createNode(int orient) {
        BNode node=new HorizontalBNode();


        //initial graph size for the node drawer
        if(sizes!=null){
            Rectangle graphBound = sizes.getGraphBound(this.getOrient());
            if(graphBound!=null){
                node.setGraphBound(graphBound);
            }
        }

 
        if(this.leafs!=null){
            int nbleafs = nbLeafCluster;
            node.setNumOfLeaf(nbleafs);
            updateSimilarities(minsim,maxsim, node);
        }

        if(this.node!=null){
            node.setShowdetail(this.node.isShowdetail() );
        }

        node.setOrient(orient);//must call after set graphBound and numOfleafs for node since it will invoke call computeDefaultLeafsLocation()
        return node;
    }

    private void updateSimilarities(double minsim,double maxsim, BNode node) {
       /* double[] maxSim = clustermodel.getMaxSimilarity();
        double maxsim=maxSim[1];
        double minsim = clustermodel.getMinSimilarity();
*/
        node.setMaxSimilarity(maxsim);
        node.setMinSimilarity(minsim);
    }


    protected void setsizes(Dimension compSize){
        sizes.setPlotsize(compSize);
        Rectangle graphBound = sizes.getGraphBound(this.getOrient());




        node.setGraphBound(graphBound);//


    }

  /*  public void setClustermodel(ClusterModel clustermodel) {
        this.clustermodel = clustermodel;

        int nbleafs = clustermodel.getNbLeafCluster();
        this.node.setNumOfLeaf(nbleafs);
        updateSimilarities(minsim,maxsim,node);
        this.repaint();

    }*/
    public void setClustermodel( int nbleafs, double minsim, double maxsim ) {
        this.minsim=minsim;
        this.maxsim=maxsim;

        this.node.setNumOfLeaf(nbleafs);
        updateSimilarities(minsim,maxsim,node);
        this.repaint();

    }
    private void printLeaf(List<LCluster> leafs){
        for (Iterator iterator = leafs.iterator(); iterator.hasNext();) {
            LCluster leaf = (LCluster) iterator.next();
            String dataId = leaf.getId();
            int dataIndex = leaf.getDtIndex();
            System.out.println("    node-"+dataIndex+" : "+dataId);
        }

    }
    public void setLeafsInterval(double[] leafsInterval) {
        this.node.setLeafsInterval(leafsInterval);
        this.repaint();
    }

   /*******************************************************************************************************
    *                paint
    *******************************************************************************************************/
    /**
     *
     */
    public void repaint(){
        super.repaint();
    }

    /* public void paintComponent(Graphics g){
        super.rp
        Graphics2D g2d=(Graphics2D) g;
        //paintFrame(g2d);

        paintTree(g2d);



    }*/

    public  void paintComponent(Graphics g2d) {
        /*  AffineTransform oldtrm = new AffineTransform();
      oldtrm.translate(-50,-50);
       g2d.setTransform(offset); */ //




        long startpaint=0;
        long endpaint=0;
       
        //node.setSize(5);
        Color oldcolor = g2d.getColor();
        //paintBackground(g2d);


        if(rnode !=null){

            Dimension plotsize = this.sizes.getPlotsize();
            g2d.clearRect(0,0,plotsize.width ,plotsize.height ); //todo MUST, otherwise keep the previous painting . need think why
            g2d.setColor(Color.black);
            node.drawCluster((Graphics2D) g2d, rnode);
        }
        g2d.setColor(oldcolor);

        //g2d.setTransform(oldtrm);
    }
    private void paintGraphBackground(Graphics g2d) {
        Color oldcolor = g2d.getColor();
        Rectangle bd = this.sizes.getGraphBound(this.getOrient() );
        g2d.setColor(new Color(200,200,200));
        g2d.fillRect(bd.x,bd.y,bd.width ,bd.height );
        g2d.setColor(oldcolor);
    }
    private void paintHeader(Graphics g2d){
       // Dimension headoffset = this.sizes.getHeadoffset();
        Rectangle hdbd = sizes.getHeadBound(this.getOrient());
        Color old = g2d.getColor();
        g2d.setColor(Color.pink );
        g2d.drawRect(hdbd.x,hdbd.y,hdbd.width,hdbd.height);
        g2d.setColor(old);

    }
    private void paintFoot(Graphics g2d){
       // Dimension headoffset = this.sizes.getFootoffset();
        Rectangle ftbd = sizes.getFootBound(this.getOrient());
        Color old = g2d.getColor();
        g2d.setColor(Color.green );
        g2d.drawRect(ftbd.x,ftbd.y,ftbd.width,ftbd.height);
        g2d.setColor(old);

    }


    /*******************************************************************************************************
     *                Bars
     *******************************************************************************************************/
     public String updateBarLocationChange(Point loc) {
        double similarity = node.getSimilarity(loc);
        this.node.setSimilarityThreshold(similarity);
        this.repaint();
        return "Similarity \n "+ similarity;
    }

    public void updateOnBardragFinish(){
        Set <Integer> ids=new HashSet();// ids of data whose leaf node have similarity >= threshold set by bar
        float threshold = (float) this.node.getSimilarityThreshold();
        List leafs = this.leafs;
        for (Iterator iterator = leafs.iterator(); iterator.hasNext();) {
            LCluster leaf = (LCluster) iterator.next();
            if(leaf.getSimilarity() >=threshold){
                int leafindex = leaf.getLfindex() ;
                ids.add(leafindex);
            }
        }

        this.prop.firePropertyChange(new PropertyChangeEvent(this,Change_BarSetting,null,ids) );

    }
    public void addBarListener(PropertyChangeListener p){
        prop.addPropertyChangeListener(p);
    }
    /*******************************************************************************************************
     *                setter getter
     *******************************************************************************************************/
    /**
     *
     * @param showdetail
     */
    public void setShowdetail(boolean showdetail){
        this.node.setShowdetail(showdetail);
        this.repaint();
    }
    public void setNode(BNode node) {
        this.node = node;
    }

    public PlotSize getSizes() {
        return sizes;
    }

    public void setSizes(PlotSize sizes) {
        this.sizes = sizes;
    }

    public int getOrient() {
        return orient;
    }

    public int getDistance() {
        return distance;
    }

    public List<Point> getLeafsloc() {
        return leafsloc;
    }

    


}